/**
 * @widoc $.fn.initDropTree
 * @namespace comp
 * @des 初始化下拉树组件，调用此方法的文本框不需定义 name，即使定义也不可与 opts.name 相同
 * @type function
 * @demo initDropTree/demo0 下拉树
 * @param {object} opts
 * @param {string} opts.name 必须，初始化完成后，会在 el 后生成 <input type="hidden" name="name" />，以便表单取值
 * @param {string=} opts.txtField 数据显示在文本框中的字段名称，同时作为下拉树中的显示字段，默认为 'name'
 * @param {string=} opts.valField 数据值的字段名称，用于表单取值，默认为 'val'
 * @param {int=} opts.width 弹出树的宽度，单位：px，默认为 205（css 中由.dropSel 决定）
 * @param {int=} opts.height 默认最大高度为 150，单位：px
 * @param {boolean=} opts.mulChk 是否为复选，默认为 false
 * @param {object} opts.filter 过滤功能配置，未定义时不支持过滤
 * @param {string|Array} opts.filter.fields 参与过滤的属性名，默认为 opts.txtField
 * @param {boolean} opts.filter.pySupport 是否支持拼音首字过滤，开启过滤时，默认为 true
 * @param {string=} opts.filter.placeholder 过滤搜索框占位符(不支持IE8,9)
 * @param {boolean} opts.filter.hide 是否隐藏不符合过滤条件的节点，默认为 false，复选时此属性无效
 * @param {Array=} opts.selParams 默认选中项条件 [key,value]，其中 value 支持 Array
 * @param {boolean=} opts.initTrigger 初始化时是否触发 callback（新增），默认为 true
 * @param {object} opts.treeOpts 下拉弹出的树的初始化参数，参考 $.fn.initZTree(opts)
 *       其中部分参数默认值不同：
 *         opts.treeOpts.initSelect 默认值为 false，即单选时若无匹配选中项，不默认选中
 *       其中部分参数失效：
 *         opts.treeOpts.filterEl（若定义了 opts.treeOpts.filter，则自动指向下拉弹出的搜索框）
 *         opts.treeOpts.filter 由 opts.treeOpts.filter 决定
 *         opts.treeOpts.multi 由 opts.mulChk 决定
 *         opts.treeOpts.selParams 由 opts.selParams 决定
 *         opts.treeOpts.key.name 由 opts.txtField 决定
 * @param {object} opts.dpOpts 下拉弹出框的初始参数，参考 $.fn.dropdown(opts)
 *       其中部分参数默认值不同：
 *         opts.dpOpts.modal 默认值为 false，即默认为非模态下拉框。
 *       其中部分参数失效：
 *         opts.dpOpts.cont 组件自动生成
 *         opts.dpOpts.noDestroy 始终为 true
 *         opts.dpOpts.show 始终为 false
 *         opts.dpOpts.beforeClose 组件中处理
 *         opts.dpOpts.beforeShow 组件中处理
 * @param {function(selData)=} opts.chkselFilter  mulChk=true时生效，修改选中项后对需显示的选中项过滤，返回真正的选中值
 * @param {function(selData)=} opts.callback 值改变时的回调方法
 *       selData 单选时为选中项的数据对象，无选中则为 undefined；多选时为选中对象数组，无选中则为 []
 * @return {object} obj 返回对象
 * @rtn {function} obj.setSel(selParams,clear,trigger): 设置选中项，类似 initZTree 方法中的 setSel(selParams,clear)
 *      -   trigger {boolean=} 是否触发 callback，默认为 true
 * @rtn {function} obj.resetTree(url,urlArgs,selParams): 重置数据源，同 initZTree 方法中的 reset(url,urlArgs,selParams)
 * @rtn {function} obj.resetTree(data,selParams): 重置数据源，同 2.3.11 initZTree 方法中的 reset(data,selParams)
 * @rtn {function} obj.getTreeObj 获取当前下拉树的对象，返回值即为 2.3.11 initZTree 的返回值 obj
 */
$.fn.initDropTree = function(opts){
    var CONF = {emptyH: 2};// 没有选项时的高度
    var el = $(this);// 触发下拉的元素
    opts = $.extend({
        txtField: 'name', // data 中每个数据显示的字段名称
        valField: 'val', // data 中每个数据值的字段名称
        //name:'', // 必须，下拉框中复选/单选元素的 name 属性值，初始化完成后，会在 el 后生成 <input type="hidden" name="name" />，以便表单取值
        //width:0,// 弹出树的宽度
        height: 150, // 默认高度为 150px
        mulChk: false, // 默认为单选
        //filter: {},
        //selParams: [key,value],// 第一次弹出的选中项条件[key,value]，value 支持数组
        initTrigger: true,// 初始化时是否触发 callback，同时将影响 resetTree 后的
        //chkselFilter:function(selData),// mulChk=true时生效，修改选中项后对需显示的选中项过滤，返回真正的选中值(为解决允许勾选父级以全选子节点，但不允许父级作为选中项)
        //callback: function(selData),// 确定按钮的回调，单选时为选中项的数据对象，无选中则为 undefined；多选时为选中对象数组，无选中则为 []
        treeOpts: {},
        dpOpts: {}// dropdown 扩展配置
    }, opts);
    var bTrigger;// 是否触发 callback 回调
    var guid = $.generateGuid('dropTree');
    !opts.name && (opts.name = guid);
    var hideEl;// 隐藏元素，用于表单取值
    var returnObj = {};// 返回对象
    var dpObj// dropdown 返回接口
        , dpEl// 下拉弹出层 jquery 对象
        , _treeObj;// 树对象
    var _setInputVal = function(){
        if(!_treeObj) return;
        var selData = _treeObj.getSelectedNodesNoHalf();
        var txtField = opts.txtField
            , valField = opts.valField;
        var txtStr = '', valStr = '';
        if(opts.mulChk && opts.chkselFilter){// 仅在多选时处理，单选请使用 treeOpts.selector 实现
            selData = opts.chkselFilter(selData);
        }
        if(selData){
            var selDatas = opts.mulChk ? selData : [selData];
            for(var i = 0, node, len = selDatas.length; i < len; i++){
                node = selDatas[i];
                if(valStr){
                    txtStr += ';';
                    valStr += ';';
                }
                txtStr += node[txtField];
                valStr += node[valField];
            }
        }
        hideEl.val(valStr);
        el.val(txtStr);
        el.attr('title', txtStr);
        if(bTrigger){
            opts.callback && opts.callback(selData);// 修改选中项时的回调
        }
        bTrigger = true;
    };
    var _initTree = function(){
        _treeObj = dpEl.find('#' + guid).initZTree(opts.treeOpts);
    };
    var _init = function(){
        // 下拉框内容主体字符串
        var getDropStr = function(){
            var str = '<div class="dropdown dropSel">';
            var boxH = opts.height - CONF.emptyH,
                boxW = opts.width;
            if(opts.filter){
                boxH -= 30;
                str += '<input class="dropSel-filter" value="" />';
            }
            str += '<ul class="dropSel-box ztree" style="' + (boxW ? 'width:' + boxW + 'px;' : '') + 'height: ' + boxH + 'px;" id="' + guid + '"></ul>' +
                '</div>';
            return str;
        };
        bTrigger = opts.initTrigger;// TODO initZTree 中初始化时目前一定会触发 onSelect，进入 _setInputVal 方法，因此初始时将 bTrigger 定为 opts.initTrigger 即可，reset 时也应做此操作
        // 下拉框中的内容部分
        dpEl = $(getDropStr());
        // 处理树初始化参数
        var treeOpts = opts.treeOpts;
        treeOpts = $.extend(treeOpts, {
            multi: opts.mulChk,
            initSelect: treeOpts.initSelect || false,
            selParams: opts.selParams,
            key: $.extend(treeOpts.key || {}, {name: opts.txtField})
        });
        if(opts.filter){
            treeOpts.filterEl = dpEl.find('.dropSel-filter');
            treeOpts.filter = opts.filter;
        }
        treeOpts.onSelect = opts.mulChk ? _setInputVal :
            function(){
                _setInputVal();
                dpObj.isShown() && dpObj.close();// 单选设置选中项后关闭
            };
        // 隐藏域
        hideEl = $('<input type="hidden" name="' + opts.name + '" />');
        el.prop('readonly', true)// 禁止输入
          .attr('autocomplete', 'off')
          .after(hideEl);// 添加隐藏域
        dpObj = el.dropdown($.extend(
            {
                modal: false
            },
            opts.dpOpts,
            {
                cont: dpEl,
                noDestroy: true,
                show: false,
                beforeClose: $.noop,
                beforeShow: $.noop
            }
        ));
        _initTree();
        el.off('click.showDp').on('click.showDp', function(){
            if(dpObj && !dpObj.isShown()){
                dpObj.show();
                if(!_treeObj){
                    _initTree();
                }
            }
        });
    };
    /**
     * 更新树数据源，重新初始化树 reset(url,urlArgs,selParams);reset(data,selParams)
     * @param url {string|Array=}
     * @param urlArgs {object|Array=}
     * @param selParams {Array=} 默认选中项条件 [key,value]
     */
    returnObj.resetTree = function(url, urlArgs, selParams){
        bTrigger = opts.initTrigger;// TODO initZTree 中初始化时目前一定会触发 onSelect，进入 _setInputVal 方法，因此初始时将 bTrigger 定为 opts.initTrigger 即可，reset 时也应做此操作 - 此处暂不考虑通过此方法只设置 selParams 的情况
        _treeObj && _treeObj.reset(url,urlArgs,selParams);
    };
    returnObj.setSel = function(selParams, clear, trigger){
        if(trigger === false){
            bTrigger = false;
        }
        _treeObj && _treeObj.setSel(selParams, clear);
    };
    returnObj.getTreeObj = function(){
        return _treeObj;
    };
    _init();
    return returnObj;
};